package com.keray.web.push.store;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;

import javax.websocket.Session;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author by keray
 * date:2021/7/23 10:51 上午
 * <p>
 * index 索引
 */
@Slf4j
public abstract class AbstractSocketDataStore implements SocketDataStore {

    private int sessionIndex = 0;

    // 存储本机连接的所有session
    protected final Map<Integer, Session> sessionData = new HashMap<>();

    private static final Object ADD_AND_DELETE_CLOCK = new Object();

    @Override
    public LinkedList<Session> serviceAndUidSession(String service, String uid) {
        var indexList = uidSessionIndexes(service, uid);
        if (indexList.isEmpty()) {
            return new LinkedList<>();
        }
        return indexList.stream().map(sessionData::get).collect(Collectors.toCollection(LinkedList::new));
    }


    @Override
    public int insertSession(Session session, String service, String uid) {
        int resultIndex;
        int size = 0;
        synchronized (ADD_AND_DELETE_CLOCK) {
            if (sessionData.size() > 10000) {
                resultIndex = -1;
            } else {
                if (sessionIndex >= Integer.MAX_VALUE) {
                    sessionIndex = 0;
                }
                int index = sessionIndex;
                sessionData.put(index, session);
                resultIndex = sessionIndex++;
                size = sessionData.size();
            }
        }
        if (resultIndex == -1) {
            log.info("session存储已满 现在的index={}", sessionIndex);
        } else {
            log.info("新增session连接，index={},service={},uid={},目前size={}", resultIndex, service, uid, size);
        }
        return resultIndex;
    }

    @Override
    public boolean removeSession(Session session, String service, String uid) {
        if (session == null) throw new RuntimeException("session不能为空");
        int size;
        var index = sessionIndex(session, service, uid);
        synchronized (ADD_AND_DELETE_CLOCK) {
            var s = sessionData.remove(index);
            try {
                s.close();
            } catch (Exception e) {
                log.error("session close失败:{}", e.getMessage());
            }
            size = sessionData.size();
        }
        log.info("移除session service={},uid={},index={}, 目前size={}", service, uid, index, size);
        return true;
    }

    public boolean removeSession(String service, String uid) {
        var indexes = uidSessionIndexes(service, uid);
        if (CollUtil.isEmpty(indexes)) return true;
        int size;
        synchronized (ADD_AND_DELETE_CLOCK) {
            for (var i : indexes) {
                var s = sessionData.remove(i);
                if (s != null) {
                    try {
                        s.close();
                    } catch (Exception e) {
                        log.error("session close失败:{}", e.getMessage());
                    }
                }
            }
            size = sessionData.size();
        }
        log.info("移除uid全部session service={},uid={}, 剩余size={}", service, uid, size);
        return true;
    }

    protected Integer sessionIndex(Session session, String service, String uid) {
        for (var i : uidSessionIndexes(service, uid)) {
            var s = sessionData.get(i);
            if (s != null && s.getId().equals(session.getId())) {
                return i;
            }
        }
        return null;
    }

    protected abstract LinkedList<Integer> uidSessionIndexes(String service, String uid);

}
